package com.intretech.umsin.datasource.codemapping.service.impl;


import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.intretech.umsin.common.utils.CUtils;
import com.intretech.umsin.common.utils.ReflectionUtils;
import com.intretech.umsin.datasource.codemapping.entity.CodeNameMap;
import com.intretech.umsin.datasource.codemapping.service.CodeMappingDBService;
import com.intretech.umsin.datasource.util.SqlHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.List;

/**
 * @version V1.0
 * @ClassName: CodeMappingDBServiceImpl
 * @Description:
 * @author: 李启联
 * @date: 2020-05-25 11:21
 * @Copyright: Copyright (c), 2020
 */
@CacheConfig(cacheNames="CODE_NAME_MAPS")
@Service
public class CodeMappingDBServiceImpl implements CodeMappingDBService {

    @Autowired
    SqlHelper sqlHelper;

    /**
     * 得到目标映射对象 Code-Name 码名信息
     *
     * @param targetClassKeyProperty   名"在需要查找目标对象所对应的键(Key)属性名
     * @param targetClassFieldProperty "名"在需要查找目标对象所对应的字段属性名
     * @param targetClass              "名"需要查找目标对象类型
     * @param targetClassName          "名"需要查找目标对象全类名
     * @param fieldCodePropertyVal     "码"在类中对应的字段对应的值,为减轻数据库压力(在方法返回列表对象时，一次性返回)
     * @return
     */
    @Override
    //@Cacheable(key="#targetClass +':'+#targetClassFieldProperty+':'+#fieldCodePropertyVal",unless="#result==null")
    public CodeNameMap getCodeNameMapFromDB(String targetClassKeyProperty, String targetClassFieldProperty, Class targetClass, String targetClassName, Object fieldCodePropertyVal) {
        if(fieldCodePropertyVal == null){
            return null;
        }
        Object targetObj = getTargetObject(targetClass,fieldCodePropertyVal.toString());
        Object code =null , name = null ;
        if(null != targetObj) {
            if(targetClassKeyProperty.contains(".")){
                code = ReflectionUtils.getTargetValue(targetObj, targetClassKeyProperty);
            }else {
                code = ReflectionUtils.getFieldValue(targetObj, targetClassKeyProperty);
            }
            name = ReflectionUtils.getFieldValue(targetObj, targetClassFieldProperty);
            CodeNameMap codeNameMap = new CodeNameMap(code,name);
            return codeNameMap;
        }
        return null;
    }


    @Override
    @Cacheable(key="#p0+'_'+#id",unless="#result==null")
    public Object getTargetObject(Class targetClass, String id) {
        QueryWrapper wrapper = new QueryWrapper<>();
        wrapper.select(targetClass,i ->{return true;}).eq("id",id);
        //Object entity = dynamicMapper.selectOne(wrapper);
        //return entity;
        return null;
    }

    @Override
    @Cacheable(key="#p0+'_'+#targetClassKeyProperty+'_'+#targetVal",unless="#result==null")
    public Object getTargetObjectV2(Class targetClass, String targetClassKeyProperty, String targetVal) {
        List<Object> objects = null;//dynamicMapper.selectList(wrapper);
        try {
            String sql =" select *  from " + getTableNameByClass(targetClass) +" where " + getDbColumnNameByTargetClassKeyProperty(targetClass,targetClassKeyProperty)  +" = '" + targetVal+"' ";
            objects = sqlHelper.queryForList(sql,targetClass);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if(!CollectionUtils.isEmpty(objects))
            return objects.get(0);
        return null;
    }

    /***
     * 得到目标实体对象在数据库中对应的表名称
     * @param targetClass 目标实体对象类型
     * @return 目标实体对象在数据库中对应的表名称
     * @throws Exception
     */
    private String getTableNameByClass(Class targetClass) throws Exception {

        if(Class.forName(targetClass.getTypeName()).isAnnotationPresent(TableName.class)){
            TableName tableName = Class.forName(targetClass.getTypeName()).getAnnotation(TableName.class);
            return tableName.value();
        }
        return targetClass.getSimpleName();

    }

    /**
     *
     * @param targetClass
     * @param targetClassKeyProperty
     * @return
     */
    private String getDbColumnNameByTargetClassKeyProperty(Class targetClass,String targetClassKeyProperty){

        Field field = getField(targetClass,targetClassKeyProperty);
        if (field == null) { return CUtils.camelToUnderline(targetClassKeyProperty);}

        if(field.isAnnotationPresent(TableField.class)){
            TableField tableField = field.getAnnotation(TableField.class);
            return tableField.value();
        }

        return CUtils.camelToUnderline(targetClassKeyProperty);
    }

    private Field getField(Class targetClass,String targetClassKeyProperty){
        for(Class<?> superClass = targetClass; superClass != Object.class; superClass = superClass.getSuperclass()){
            try {
                return superClass.getDeclaredField(targetClassKeyProperty);
            } catch (NoSuchFieldException e) {
                //Field 不在当前类定义, 继续向上转型
            }
        }
        return null;
    }

}